package cn.cxq.learning.array;

import org.junit.jupiter.api.Test;

/**
 * 二维数组中的查找
 * 链接：https://www.nowcoder.com/questionTerminal/abc3fe2ce8e146608e868a70efebf62e
 * 来源：牛客网
 * <p>
 * 在一个二维数组中（每个一维数组的长度相同），每一行都按照从左到右递增的顺序排序，每一列都按照从上到下递增的顺序排序。请完成一个函数，输入这样的一个二维数组和一个整数，判断数组中是否含有该整数。
 * [
 * [1,2,8,9],
 * [2,4,9,12],
 * [4,7,10,13],
 * [6,8,11,15]
 * ]
 * 给定 target = 7，返回 true。
 * <p>
 * 给定 target = 3，返回 false。
 */
public class TDArraySearch {

    @Test
    public void testFind() {
        System.out.println(Find(0, new int[][]{{}}));
        System.out.println(Find(102, new int[][]{{1, 2, 4, 6, 8, 10, 11, 13, 15, 17, 20, 22, 24, 27, 30, 32, 35, 36, 38, 39, 42, 44, 46, 47, 48, 49, 51, 54, 55, 56}, {3, 4, 6, 8, 11, 13, 15, 18, 19, 20, 23, 25, 27, 29, 33, 36, 38, 41, 42, 45, 48, 50, 53, 54, 57, 60, 63, 65, 66, 67}, {5, 7, 8, 11, 14, 15, 17, 19, 21, 23, 24, 28, 31, 33, 36, 39, 41, 44, 47, 49, 52, 53, 56, 57, 60, 63, 66, 68, 71, 72}, {7, 10, 13, 14, 17, 19, 22, 25, 26, 27, 30, 32, 34, 37, 39, 42, 44, 46, 50, 53, 55, 56, 59, 61, 64, 66, 69, 72, 74, 76}, {8, 12, 16, 17, 20, 21, 23, 26, 29, 31, 33, 35, 37, 40, 42, 45, 48, 49, 52, 55, 58, 59, 61, 63, 67, 69, 70, 74, 76, 79}, {10, 15, 18, 20, 22, 24, 27, 30, 32, 33, 36, 38, 39, 41, 45, 47, 50, 53, 56, 58, 61, 64, 65, 68, 69, 71, 73, 76, 79, 82}, {13, 17, 20, 23, 24, 26, 28, 31, 34, 36, 38, 41, 42, 43, 48, 50, 53, 56, 58, 61, 64, 67, 68, 71, 73, 74, 75, 78, 81, 84}, {15, 19, 22, 24, 26, 28, 31, 34, 35, 38, 41, 44, 45, 46, 49, 51, 56, 59, 61, 64, 67, 69, 71, 73, 76, 78, 79, 82, 85, 87}, {17, 20, 23, 26, 29, 30, 32, 37, 40, 42, 43, 47, 50, 53, 55, 56, 58, 62, 64, 66, 69, 72, 75, 78, 80, 81, 83, 86, 88, 90}, {18, 21, 25, 28, 30, 32, 35, 38, 42, 43, 44, 49, 51, 55, 58, 59, 61, 65, 68, 71, 73, 74, 77, 79, 82, 85, 88, 89, 91, 93}, {20, 23, 28, 29, 33, 36, 37, 40, 43, 45, 47, 52, 55, 58, 60, 62, 63, 66, 70, 74, 76, 77, 79, 81, 85, 88, 89, 91, 93, 94}, {23, 25, 31, 33, 35, 39, 42, 43, 44, 46, 50, 53, 56, 61, 62, 65, 68, 69, 72, 75, 78, 81, 82, 83, 88, 91, 92, 93, 96, 99}, {26, 27, 33, 34, 38, 40, 45, 48, 51, 53, 55, 56, 58, 64, 66, 69, 72, 75, 77, 80, 82, 84, 87, 88, 90, 93, 94, 95, 99, 101}, {29, 30, 36, 38, 40, 42, 47, 50, 53, 56, 57, 59, 62, 65, 68, 71, 73, 77, 79, 83, 84, 86, 88, 91, 93, 96, 99, 100, 102, 103}, {32, 33, 39, 42, 44, 46, 49, 53, 56, 59, 62, 65, 68, 71, 72, 75, 77, 78, 80, 85, 87, 90, 92, 94, 96, 99, 101, 103, 105, 107}, {35, 37, 42, 43, 46, 48, 51, 55, 59, 61, 65, 67, 71, 74, 76, 78, 81, 82, 84, 86, 90, 92, 95, 96, 99, 102, 103, 106, 107, 109}, {36, 39, 43, 46, 49, 50, 53, 58, 62, 65, 67, 70, 73, 76, 77, 79, 84, 87, 88, 90, 93, 96, 99, 102, 103, 106, 108, 111, 112, 115}, {38, 42, 45, 47, 52, 55, 57, 60, 64, 66, 69, 72, 75, 78, 80, 82, 87, 89, 91, 92, 94, 99, 100, 103, 105, 107, 111, 112, 115, 118}, {39, 44, 48, 49, 55, 57, 60, 63, 66, 69, 72, 75, 78, 80, 82, 85, 89, 92, 94, 95, 98, 101, 102, 105, 108, 111, 112, 115, 116, 120}, {40, 47, 49, 52, 56, 59, 63, 64, 68, 71, 75, 78, 80, 83, 85, 88, 91, 94, 97, 99, 101, 104, 105, 108, 110, 112, 115, 118, 120, 123}, {42, 50, 53, 55, 59, 62, 66, 67, 71, 73, 78, 81, 82, 86, 87, 90, 94, 97, 100, 101, 104, 106, 107, 109, 111, 114, 117, 120, 123, 126}, {43, 51, 55, 58, 62, 64, 69, 71, 74, 77, 81, 84, 86, 87, 89, 93, 96, 99, 102, 103, 105, 108, 111, 112, 113, 116, 120, 122, 125, 129}, {45, 54, 56, 59, 65, 67, 72, 75, 76, 79, 84, 87, 90, 92, 94, 97, 99, 102, 104, 107, 108, 111, 114, 116, 119, 120, 122, 124, 127, 132}, {47, 55, 59, 62, 66, 68, 74, 78, 80, 82, 85, 88, 93, 96, 99, 101, 102, 105, 106, 108, 110, 113, 115, 118, 120, 121, 124, 127, 130, 133}, {49, 56, 61, 65, 68, 70, 76, 81, 83, 85, 87, 91, 95, 99, 102, 103, 104, 106, 108, 110, 113, 116, 118, 121, 124, 127, 130, 133, 134, 137}, {51, 57, 62, 68, 71, 74, 78, 83, 86, 89, 92, 95, 97, 101, 104, 106, 108, 110, 113, 114, 117, 119, 121, 123, 126, 130, 132, 135, 137, 140}, {53, 59, 65, 69, 73, 75, 81, 86, 88, 92, 95, 97, 100, 103, 107, 109, 111, 112, 115, 117, 120, 122, 125, 126, 129, 131, 133, 138, 141, 143}, {55, 61, 67, 72, 75, 77, 82, 89, 92, 94, 97, 100, 102, 105, 108, 111, 114, 115, 116, 119, 123, 125, 126, 128, 131, 134, 137, 140, 144, 146}, {57, 63, 68, 74, 78, 81, 85, 90, 95, 98, 100, 101, 103, 107, 110, 114, 117, 119, 120, 123, 126, 129, 130, 133, 136, 138, 141, 144, 146, 149}, {58, 65, 70, 76, 81, 84, 86, 93, 98, 101, 104, 105, 107, 110, 112, 115, 120, 122, 124, 126, 129, 132, 135, 136, 138, 140, 142, 146, 149, 150}}));
    }

    //从左下角开始找，如果找到了就返回true，比它大了就向上走，比他小了就向右走，出界了就返回false。
    private boolean Find(int target, int[][] array) {
        if (array.length == 0 || array[0].length == 0) {
            return false;
        }

        int i = array.length - 1;
        int j = 0;

        while (i >= 0 && i < array.length && j >=0 && j < array[0].length) {
            if (target == array[i][j]) {
                return true;
            } else if (target > array[i][j]) {
                j++;
            } else {
                i--;
            }
        }

        return false;
    }

    //看题解之后的改善：从数组最后一行开始判断（是否有点贪心的味道？追求最佳情况：即遍历最少的次数），如果第一个位置的元素比target大的话就跳过该行的查找，如果等于就返回true，再者就使用二分查找查找是否有该数。
//    private boolean Find(int target, int[][] array) {
//
//        if (array.length == 0 || array[0].length == 0) {
//            return false;
//        }
//
//        for (int i = array.length - 1; i >= 0; i--) {
//            if (array[i][0] == target) {
//                return true;
//            }
//            if (array[i][0] < target) {
//                int left = 0;
//                int right = array[i].length - 1;
//                int mid = (left + right) / 2;
//                while (left <= right) {
//                    if (array[i][mid] == target) {
//                        return true;
//                    } else if (array[i][mid] > target) {
//                        right = mid - 1;
//                        mid = (left + right) / 2;
//                    } else {
//                        left = mid + 1;
//                        mid = (left + right) / 2;
//                    }
//                }
//            }
//        }
//
//        return false;
//    }

    //思路：找对角线的元素看看是否比它大，（排除了一些意外情况）然后再遍历右上和左下的矩阵找找有没有要找的数。
//    public boolean Find(int target, int[][] array) {
//
//        if (array.length == 0 || array[0].length == 0) return false;
//
//        int i = 0;
//
//        while (i < array.length && i < array[i].length) {
//            if (array[i][i] < target) {
//                i++;
//            } else if (array[i][i] == target) {
//                return true;
//            } else {
//                break;
//            }
//        }
//
//        if (i == array.length) {
//            i -= 1;
//            int j = i + 1;
//            while (j < array[i].length) {
//                if (array[i][j] < target) {
//                    j++;
//                } else {
//                    break;
//                }
//            }
//
//            if (j == array[i].length) return false;
//
//            if (array[i][j] == target || array[i][j - 1] == target) {
//                return true;
//            }
//        }
//
//        if (i == array[i].length) {
//            i -= 1;
//            int j = i + 1;
//            while (j < array.length) {
//                if (array[j][i] < target) {
//                    j++;
//                } else {
//                    break;
//                }
//            }
//
//            if (j == array.length) return false;
//
//            if (array[j][i] == target || array[j - 1][i] == target) {
//                return true;
//            }
//        }
//
//        int index = i;
//        for (int j = index; j >= 0; j--) {
//            for (int k = index; k < array.length; k++) {
//                if (array[k][j] == target) {
//                    return true;
//                }
//                if (array[j][k] == target) {
//                    return true;
//                }
//            }
//
//        }
//        return false;
//    }


}
